
#include "Profiler.h"
#include <map>
#include <cmath>
#include <stdio.h>
#include <sstream>

#ifdef _WIN32
    // under windows
    #include <windows.h>
#else 
    // under nix
    #include <time.h>
#endif

using namespace std;

typedef map<std::string, double> Map;
typedef Map::iterator MapIterator;	

static Map lenghts;
static map<string, size_t> counts;
static Map startTimes;

//-----------------------------------------------------------------------------
double getTime() {
#ifdef _WIN32
    // under windows
    long long frequency, counter;
    QueryPerformanceFrequency((LARGE_INTEGER*)&frequency);
    QueryPerformanceCounter((LARGE_INTEGER*)&counter);	
    return ((double)counter) / frequency;
#else 
    // under nix
    timespec time;
    clock_gettime(CLOCK_REALTIME, &time);
    return time.tv_nsec / 1000000000.0;
#endif
}

//-----------------------------------------------------------------------------
double Profiler::getLenght(const string &name) {
    return lenghts[name];            
}

//-----------------------------------------------------------------------------
size_t Profiler::getCount(const string &name) {
    return counts[name];
}

//-----------------------------------------------------------------------------
void Profiler::start(const string &name) {
    startTimes[name] = getTime();
}

//-----------------------------------------------------------------------------
void Profiler::stop(const string &name) {
    double time = abs(getTime() - startTimes[name]);
	addTime(name, time);
}

//-----------------------------------------------------------------------------
void Profiler::addTime(const std::string &name, double time) {
	MapIterator found = lenghts.find(name);
    if (found != lenghts.end()) {
        found->second += time;
        counts[name]++;
    } else {
        lenghts[name] = time;
        counts[name] = 1;
    }
}

//-----------------------------------------------------------------------------
string Profiler::print() {	
	stringstream out;	
    for (MapIterator i = lenghts.begin(); i != lenghts.end(); i++) {
		out << i->first << " called " << counts[i->first] << " times; total " << i->second << " seconds\n";
    }
    return out.str();
}

//-----------------------------------------------------------------------------
void Profiler::clear() {
    lenghts.clear();
    counts.clear();
}

//-----------------------------------------------------------------------------
Measure::Measure(const std::string& _name) : name(_name) {
	Profiler::start(name);
}
	
//-----------------------------------------------------------------------------
Measure::~Measure() {
	Profiler::stop(name);
}

//-----------------------------------------------------------------------------
Measure::Measure(Measure&) {}

//-----------------------------------------------------------------------------
Measure& Measure::operator =(Measure&) { return *this; }